﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Text;
using static M.Core.RmoteCall.RpcCall.RpcServiceInfo;
using System.Collections;
using System.Threading.Tasks;

namespace M.Core.RmoteCall.RpcCall.Pool
{
    public class RpcPool
    {
        private List<RpcPoolItem> _listObjects =new List<RpcPoolItem>();
        private List<RpcPoolItem> _listFreeIndex =new List<RpcPoolItem>();
        private List<RpcPoolItem> _listUsingIndex = new List<RpcPoolItem>();


        public int initSize { get; set; }
        public int maxSize { get; set; }

        private Func<CallSocketObject> onCreate = null;
        public RpcPool(int initSize,int maxSize, Func<CallSocketObject> onCreate)
        {
            this.initSize = initSize;
            this.maxSize = maxSize;
            this.onCreate = onCreate;
            for (int i = 0; i < initSize; i++)
            {
                var item=new RpcPoolItem(this, onCreate());
                Add(item);
            }
        }
        public RpcPoolItem GetOne(ulong second=3)
        {
            DateTime dateTime = DateTime.Now;
            return GetOne(dateTime, second);
        }
        private RpcPoolItem GetOne(DateTime date, ulong second)
        {
            RpcPoolItem item = null;
            if (_listFreeIndex.Count == 0)
            {
                if (_listObjects.Count < maxSize)
                {
                    item = new RpcPoolItem(this, onCreate());
                    Add(item);
                    return GetOne(date, second);
                }

                if ((DateTime.Now - date).TotalSeconds >= second) return null;
                Task.Delay(200).GetAwaiter().GetResult();
                return GetOne(date, second);
            }

            lock (this)
            {
                item = _listFreeIndex[0];                
                _listFreeIndex.RemoveAt(0);
                item.IsUsing = true;
                _listUsingIndex.Add(item);
            }
            if (!item.IsValidate())
            {
                Remove(item);

                return GetOne(date, second);
            }

            return item;
        }
        private void Add(RpcPoolItem callModelObject)
        {
            lock (this)
            {
                callModelObject.IsUsing = false;
                _listObjects.Add(callModelObject);
                _listFreeIndex.Add(callModelObject);
            }
            
        }
        internal void ReSet(RpcPoolItem  callModelObject)
        {
            lock (this)
            {
                _listUsingIndex.Remove(callModelObject);
                callModelObject.IsUsing = false;
                _listFreeIndex.Add(callModelObject);
            }
        }

        internal void Remove(RpcPoolItem  callModelObject)
        {
            lock (this)
            {
                if (callModelObject.IsUsing)
                {
                    _listUsingIndex.Remove(callModelObject);
                }
                else
                {
                    _listFreeIndex.Remove(callModelObject);
                }
                _listObjects.Remove(callModelObject);
            }
        }

        internal void Release()
        {
            _listUsingIndex=_listFreeIndex = null;

            foreach (var item in _listObjects)
            {
                item.Release();
            }
            _listObjects = null;
        }
    }
}
